<i18n locale="zh-CN" lang="yaml">
Add Script  : 添加脚本
Setup Script: 配置脚本

Script Template     : 脚本模板
Show Script Template: 显示脚本模板
Basic Example       : 基础示例
Blank Script        : 空白脚本
From Example Script : 来自示例脚本

Script Set ID should be a prefix of the Script ID: 脚本集 ID 应作为脚本 ID 的前缀

Please input ID: 请输入 ID
Only alphabets, numbers and underscore are allowed: 只能包含大小写英文、数字及下划线
Cannot not starts with a number: 不得以数字开头
'This Script ID should starts with "{prefix}"': '本脚本 ID 必须以 "{prefix}" 开头'

Script created : 脚本已创建
Script saved   : 脚本已保存
Script deleted : 脚本已删除

Are you sure you want to delete the Script?: 是否确认删除此脚本？

This Script is locked by you: 当前脚本已被您锁定
This Script is locked by other user ({user}): 当前脚本已被其他用户（{user}）锁定
</i18n>

<!-- Generated by OpenCC START -->
<i18n locale="zh-HK" lang="yaml">
Add Script: 添加腳本
Are you sure you want to delete the Script?: 是否確認刪除此腳本？
Basic Example: 基礎示例
Blank Script: 空白腳本
Cannot not starts with a number: 不得以數字開頭
From Example Script: 來自示例腳本
Only alphabets, numbers and underscore are allowed: 只能包含大小寫英文、數字及下劃線
Please input ID: 請輸入 ID
Script Set ID should be a prefix of the Script ID: 腳本集 ID 應作為腳本 ID 的前綴
Script Template: 腳本模板
Script created: 腳本已創建
Script deleted: 腳本已刪除
Script saved: 腳本已保存
Setup Script: 配置腳本
Show Script Template: 顯示腳本模板
This Script ID should starts with "{prefix}": 本腳本 ID 必須以 "{prefix}" 開頭
This Script is locked by other user ({user}): 當前腳本已被其他用户（{user}）鎖定
This Script is locked by you: 當前腳本已被您鎖定
</i18n>
<i18n locale="zh-TW" lang="yaml">
Add Script: 新增指令碼
Are you sure you want to delete the Script?: 是否確認刪除此指令碼？
Basic Example: 基礎示例
Blank Script: 空白指令碼
Cannot not starts with a number: 不得以數字開頭
From Example Script: 來自示例指令碼
Only alphabets, numbers and underscore are allowed: 只能包含大小寫英文、數字及下劃線
Please input ID: 請輸入 ID
Script Set ID should be a prefix of the Script ID: 指令碼集 ID 應作為指令碼 ID 的字首
Script Template: 指令碼模板
Script created: 指令碼已建立
Script deleted: 指令碼已刪除
Script saved: 指令碼已儲存
Setup Script: 配置指令碼
Show Script Template: 顯示指令碼模板
This Script ID should starts with "{prefix}": 本指令碼 ID 必須以 "{prefix}" 開頭
This Script is locked by other user ({user}): 當前指令碼已被其他使用者（{user}）鎖定
This Script is locked by you: 當前指令碼已被您鎖定
</i18n>
<!-- Generated by OpenCC END -->

<template>
  <el-dialog
    id="ScriptSet"
    :visible.sync="show"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    width="750px">
    <template slot="title">
      {{ pageTitle }} <code class="text-main" v-if="pageMode === 'setup'">{{ data.title || data.id }}</code>
    </template>

    <el-container direction="vertical">
      <el-main>
        <div class="setup-form">
          <el-form ref="form" label-width="135px" :model="form" :disabled="!canSetup" :rules="formRules">
            <el-form-item v-if="isLockedByMe">
              <InfoBlock type="success" :title="$t('This Script is locked by you')" />
            </el-form-item>
            <el-form-item v-else-if="isLockedByOther">
              <InfoBlock :type="canSetup ? 'warning' : 'error'" :title="$t('This Script is locked by other user ({user})', { user: lockedByUser })" />
            </el-form-item>

            <el-form-item label="ID" prop="id">
              <el-input :disabled="pageMode === 'setup'"
                maxlength="60"
                v-model="form.id">
              </el-input>
              <InfoBlock :title="$t('Script Set ID should be a prefix of the Script ID')" />
            </el-form-item>

            <el-form-item :label="$t('Title')">
              <el-input :placeholder="$t('Optional')"
                maxlength="200"
                v-model="form.title"></el-input>
            </el-form-item>

            <el-form-item :label="$t('Description')">
              <el-input :placeholder="$t('Optional')"
                type="textarea"
                resize="none"
                :autosize="{minRows: 2}"
                maxlength="5000"
                v-model="form.description"></el-input>
            </el-form-item>

            <el-form-item :label="$t('Script Template')" v-if="pageMode === 'add'">
              <el-select
                v-model="templateScriptId"
                @change="showScriptTemplate"
                filterable
                :filter-method="T.debounce(doFilter)">
                <el-option-group>
                  <el-option :label="$t('Basic Example')" key="_basicExample" value="_basicExample"></el-option>
                  <el-option :label="$t('Blank Script')" key="_blankScript" value="_blankScript"></el-option>
                </el-option-group>
                <el-option-group :label="$t('From Example Script')" v-if="templateScriptShowOptions.length > 0">
                  <el-option v-for="s in templateScriptShowOptions" :label="s.label" :key="s.id" :value="s.id">
                    <span class="example-script">{{ s.label }}</span>
                  </el-option>
                </el-option-group>
              </el-select>

              <el-button v-if="!!templateScript" @click="showScriptTemplate" type="text">{{ $t('Show Script Template') }}</el-button>
            </el-form-item>

            <el-form-item class="setup-footer">
              <el-link type="danger" class="float-left" v-if="pageMode === 'setup'" @click="deleteData">{{ $t('Delete') }}</el-link>
              <el-button type="text" @click="showLockConfig">{{ $t('Lock') }}</el-button>
              &emsp;
              <el-button type="primary" v-prevent-re-click @click="submitData">{{ $t('Save') }}</el-button>
            </el-form-item>
          </el-form>
        </div>
      </el-main>

      <LongTextDialog :title="$t('Script Template')" mode="python" ref="longTextDialog" />
    </el-container>
  </el-dialog>
</template>

<script>
import LongTextDialog from '@/components/LongTextDialog'

export default {
  name: 'ScriptSetup',
  components: {
    LongTextDialog,
  },
  watch: {
    show(val) {
      if (val && this.$refs.form) {
        this.$refs.form.clearValidate();
      }
    },
    'form.id'(val) {
      if (!val || val.length < this.ID_PREFIX.length || val.indexOf(this.ID_PREFIX) < 0) {
        this.form.id = this.ID_PREFIX;
      }
    }
  },
  methods: {
    doFilter(q) {
      q = (q || '').toLowerCase().trim();
      if (!q || q[0] === '_') {
        this.templateScriptShowOptions = this.templateScripts;
      } else {
        this.templateScriptShowOptions = this.common.filterByKeywords(q, this.templateScripts);
      }
    },

    async loadData(scriptSetId, id) {
      this.scriptSetId = scriptSetId;

      if (!id) {
        this.pageMode = 'add';
        this.T.jsonClear(this.form);
        this.data = {};

        // Format of Script ID is "<Script Set ID>__<Script Name>"
        this.form.id = this.ID_PREFIX;

        // Load example code
        let apiRes = await this.T.callAPI_getAll('/api/v1/scripts/do/list', {
          query: {
            fields: [
              'id',
              'title',
              'scriptSetId',
              'sset_title',
              'code',
            ],
            _withCode : true,
            _isExample: true,
          },
        });
        if (!apiRes || !apiRes.ok) return;

        let templateScripts = apiRes.data;

        templateScripts.forEach(d => {
          d.shortScriptId = d.id.split('__').slice(1).join('__');
          d.label = `${d.sset_title || d.scriptSetId} / ${d.title || d.shortScriptId}`;
          this.common.appendSearchFields(d, ['sset_title', 'scriptSetId', 'title', 'shortScriptId'])
        });

        this.templateScripts           = templateScripts;
        this.templateScriptShowOptions = templateScripts;
        this.templateScriptMap = templateScripts.reduce((acc, x) => {
          acc[x.id] = x;
          return acc;
        }, {});

      } else {
        this.pageMode = 'setup';
        this.data.id = id;
        let apiRes = await this.T.callAPI_getOne('/api/v1/scripts/do/list', this.scriptId);
        if (!apiRes || !apiRes.ok) return;

        this.data = apiRes.data;

        let nextForm = {};
        Object.keys(this.form).forEach(f => nextForm[f] = this.data[f]);
        this.form = nextForm;
      }

      this.show = true;
    },
    async submitData() {
      try {
        await this.$refs.form.validate();
      } catch(err) {
        return console.error(err);
      }

      let dataId = null;
      switch(this.pageMode) {
        case 'add':
          dataId = await this.addData();
          break;

        case 'setup':
          dataId = await this.modifyData();
          break;
      }

      if (dataId) {
        this.$store.commit('updateEditor_selectedItemId', null);
      }
    },
    async addData() {
      let _data = this.T.jsonCopy(this.form);

      switch(this.templateScriptId) {
        case '_basicExample':
          delete _data.codeDraft;
          break;

        case '_blankScript':
          _data.codeDraft = '';
          break;

        default:
          let exampleScript = this.templateScriptMap[this.templateScriptId];
          _data.codeDraft = exampleScript && exampleScript.code
                          ? exampleScript.code
                          : '';
          break;
      }

      // Use Base64 to pass code
      if (_data.codeDraft) {
        _data.codeDraftBase64 = this.T.getBase64(_data.codeDraft);
        delete _data.codeDraft;
      }

      let apiRes = await this.T.callAPI('post', '/api/v1/scripts/do/add', {
        body    : { data: _data },
        feedback: { okMessage: this.$t('Script created') },
      });
      if (!apiRes || !apiRes.ok) return;

      this.$store.commit('updateScriptListSyncTime');
      this.show = false;

      this.$router.push({
        name  : 'code-editor',
        params: { id: apiRes.data.id },
      });

      return apiRes.data.id;
    },
    async modifyData() {
      let _formData = this.T.jsonCopy(this.form);
      delete _formData.id;

      let apiRes = await this.T.callAPI('post', '/api/v1/scripts/:id/do/modify', {
        params  : { id: this.scriptId },
        body    : { data: _formData },
        feedback: { okMessage: this.$t('Script saved') },
      });
      if (!apiRes || !apiRes.ok) return;

      this.$store.commit('updateScriptListSyncTime');
      this.show = false;

      return this.scriptId;
    },
    async deleteData() {
      if (!await this.T.confirm(this.$t('Are you sure you want to delete the Script?'))) return;

      this.common.jumpDeletedEntity(this.scriptId);

      let apiRes = await this.T.callAPI('/api/v1/scripts/:id/do/delete', {
        params  : { id: this.scriptId },
        feedback: { okMessage: this.$t('Script deleted') },
      });
      if (!apiRes || !apiRes.ok) return;

      this.$store.commit('updateScriptListSyncTime');
      this.show = false;
    },

    showScriptTemplate() {
      if (this.templateScript) {
        this.$refs.longTextDialog.update(this.templateScript);
      }
    },
    showLockConfig() {
      this.$parent.$refs.ScriptLockConfig.loadData(this.scriptId);

      setTimeout(() => {
        this.show = false;
      }, 150);
    },
  },
  computed: {
    ID_PREFIX() {
      return `${this.scriptSetId}__`;
    },
    pageTitle() {
      const _map = {
        setup: this.$t('Setup Script'),
        add  : this.$t('Add Script'),
      };
      return _map[this.pageMode];
    },
    scriptId() {
      switch(this.pageMode) {
        case 'add':
          return this.form.id;
        case 'setup':
          return this.data.id;
      }
    },

    lockedByUserId() {
      return this.data.lockedByUserId;
    },
    lockedByUser() {
      return this.data.lockedByUserName || this.data.lockedByUsername;
    },
    isLockedByMe() {
      return this.lockedByUserId === this.$store.getters.userId;
    },
    isLockedByOther() {
      return this.lockedByUserId && !this.isLockedByMe;
    },
    canSetup() {
      return this.common.lockConfigCan(this.lockedByUserId, this.data.lockConfigMemberAllowMap, [ 'scriptSet_setupScript', 'script_setup' ]);
    },

    templateScript() {
      if (!this.templateScriptId
        || this.T.isNothing(this.templateScriptMap)
        || !this.templateScriptMap[this.templateScriptId]) {
        return '';
      } else {
        return this.templateScriptMap[this.templateScriptId].code || '';
      }
    },
  },
  props: {
  },
  data() {
    return {
      show    : false,
      pageMode: null,

      scriptSetId: '',
      data: {},

      templateScriptId: '_basicExample',

      templateScripts          : [],
      templateScriptShowOptions: [],
      templateScriptMap        : {},

      form: {
        id         : null,
        title      : null,
        description: null,
      },
      formRules: {
        id: [
          {
            trigger : 'blur',
            message : this.$t('Please input ID'),
            required: true,
          },
          {
            trigger: 'change',
            message: this.$t('Only alphabets, numbers and underscore are allowed'),
            pattern: /^[a-zA-Z0-9_]*$/g,
          },
          {
            trigger: 'change',
            message: this.$t('Cannot not starts with a number'),
            pattern: /^[^0-9]/g,
          },
          {
            trigger: 'change',
            validator: (rule, value, callback) => {
              if (value && value.indexOf(this.ID_PREFIX) < 0 || value === this.ID_PREFIX) {
                let _message = this.$t('This Script ID should starts with "{prefix}"', { scriptSetId: this.scriptSetId, prefix: this.ID_PREFIX });
                return callback(new Error(_message));

              } else if (!(value.slice(this.ID_PREFIX.length).match(/^[^0-9]/g))) {
                let _message = this.$t('Cannot not starts with a number');
                return callback(new Error(_message));

              }
              return callback();
            },
          },
        ],
      }
    }
  },
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.example-script {
  padding-left: 20px;
}
</style>
